最开始只是想综合的初略学习下这几种技术,所以萌生了搭建一个简单的结构的想法;整个结构应该没有什么问题;已经放到了github
上,地址:webpack、sass、react、redux的简易demo入门
webpack
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
我自己对webpack
的使用也不是很熟练,还没有很明白webpack
的设计思维,所以在配置的时候也是一脸懵逼,跟着官方文档和一些社区的文章来一步一步配置,主要还是需要知道这几个配置:
- 入口(entry)
- 输出(output)
- loader
- 插件(plugins)
- 解析(Resolve)
入口(entry)
起点或是应用程序的起点入口。从这个起点开始,应用程序启动执行。如果传递一个数组,那么数组的每一项都会执行。
entry
字段可以是string | [string] | object { <key>: string | [string] }
或者是函数【函数返回值是上面的三种类型中的一种】,本次demo
的选择是对象来处理,如下:
entry: {
home: './src/scripts/pages/home/index.js'
// homecss: './src/styles/pages/home.scss' // scss入口放到最开始的js中, webpack无法处理非js文件
},
输出(output)
output 位于对象最顶级键(key),包括了一组选项,指示 webpack 如何去输出、以及在哪里输出你的「bundle、asset 和其他你所打包或使用 webpack 载入的任何内容」。
通常而言,通过 output.filename 和 output.path 属性,来告诉 webpack bundle 的名称,以及我们想要生成(emit)到哪里。demo
中的配置如:
output: {
path: path.join(__dirname + '/src/dist'),
// publicPath:'/'
// publicPath: path.join(__dirname + '/src/dist/'), // 加载外部资源,此选项指定在浏览器中所引用的「此输出目录对应的公开 URL」
filename: 'js/[name].js'
}
需要注意的是,filename: 'js/[name].js'
这么写是因为webpack
支持入口文件为多个文件时可以配置不同的输出文件名,参考output-filename
loader
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图可以直接引用的模块。
重要的是要记得,在 webpack 配置中定义 loader 时,要定义在 module.rules 中,而不是 rules。
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/stage-3', '@babel/react']
}
}
},
{
test: /\.scss$/,
use: extractSass.extract({
use: [{
loader: "css-loader"
}, {
loader: "sass-loader"
}],
// publicPath: './../', // 加载外部资源,把路径重新定义到dist目录下,而不是css里面
// use style-loader in development
fallback: "style-loader"
})
},
{
test: /\.(png|svg|jpg|gif|jpeg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
useRelativePath: true, // 图片相对路径
outputPath: 'images/'
}
}
]
}
]
}
以上是demo
的配置,在 webpack 的配置中 loader 有两个目标。
- 识别出应该被对应的 loader 进行转换的那些文件。(使用 test 属性)
- 转换这些文件,从而使其能够被添加到依赖图中(并且最终添加到 bundle 中)(use 属性)
可以看到,同一个文件可以顺序使用多个loader
来加载,每个loader
可以传递参数来进行特殊处理。
插件(plugins)
插件是 wepback 的支柱功能。webpack 自身也是构建于,你在 webpack 配置中用到的相同的插件系统之上!插件目的在于解决 loader 无法实现的其他事。
webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。
由于插件可以携带参数/选项,你必须在 webpack
配置中,向 plugins
属性传入 new 实例。根据你的 webpack
用法,这里有多种方式使用插件。插件使用,插件列表
demo
中使用了两个plugins
,extract-text-webpack-plugin
& DefinePlugin
,都是按照官方插件文档配置的。
解析(Resolve)
这些选项能设置模块如何被解析。webpack 提供合理的默认值,但是还是可能会修改一些解析的细节。关于 resolver 具体如何工作的更多解释说明,请查看模块解析方式。
简单的说,就是会帮我们弄好一些默认的选项,比如别名alias
、extensions
模块默认后缀、mainFiles
默认文件入口等;
resolve: {
mainFiles: ["index"],
extensions: ['.js', '.jsx'],
alias: {
'stylepages': path.join(__dirname + '/src/styles/pages'),
'scripts': path.join(__dirname + '/src/scripts/pages'),
'commonjs': path.join(__dirname + '/src/scripts/common')
}
}
遇到问题
关于webpack无法把css文件作为入口,需要在js中引入css,然后进行css的分离
关于sass使用@import时来使用alias别名配置的路径时不被正确解析,sass-loader需要在使用别名的前面加上~
,stylelib
是别名,使用时@import '~stylelib/base.scss';
关于sass
和图片等外部资源的打包出现的路径不一致,,有以下几种方法:
- 第一种方法,可以在配置
fileloader
的时候使用相对路径:useRelativePath
{
test: /\.(png|svg|jpg|gif|jpeg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
useRelativePath: true, // 图片相对路径
outputPath: 'images/'
}
}
]
}
- 第二种方法,在使用
ExtractTextWebpackPlugin
的时候,可以根据已有的loader来重新提取loader
,在提取新的loader
时,可以配置公共路径publicPath
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractSass = new ExtractTextPlugin({
filename: "css/[name].css",
disable: process.env.NODE_ENV === "development"
});
// loader 里面
{
test: /\.scss$/,
use: extractSass.extract({
use: [{
loader: "css-loader"
}, {
loader: "sass-loader"
}],
publicPath: './../', // 把路径重新定义到dist目录下,而不是css里面
// use style-loader in development
fallback: "style-loader"
})
}
- 第三种方法,直接在所有的输出目录处使用当前的打包路径,
publicPath
output: {
path: path.join(__dirname + '/src/dist'),
publicPath:'./'
// publicPath: path.join(__dirname + '/src/dist/'), // 加载外部资源,此选项指定在浏览器中所引用的「此输出目录对应的公开 URL」
filename: 'js/[name].js'
}
sass
Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能,这些拓展令 CSS 更加强大与优雅。使用 Sass 以及 Sass 的样式库(如 Compass)有助于更好地组织管理样式文件,以及更高效地开发项目。
使用sass可以感受到以下几点的优势:
- 合理的嵌套规则,不需要重复书写selector。
- 变量$、占位符%都可以很好的提供复用性
- 函数、运算可以很好的增加灵活性
这里就不多说sass的学习了,可以查看sass中文、sass官网
react
React 是一个采用声明式,高效而且灵活的用来构建用户界面的框架。
学习react的重要内容包括:
- jsx的书写语法
- 组件Components【props、state、Lifecycle...】
- 虚拟dom,
- 组件渲染和diff,Lists and Keys
更多的学习react学习官网
redux
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。 惟一改变 state 的办法是触发 action,一个描述发生什么的对象。 为了描述 action 如何改变 state 树,你需要编写 reducers;
- 应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中,初始时由reducer初识态来创建
- 改变state的唯一方法就是触发dispatch一个action,
- 一个action是本质上一个对象,用来把最新的数据传到store的有效载荷
- Reducer就是把action这个有效载荷解析,并应用到store之中;
具体实践中:
- 书写reducer,来确定初始时的state
- 根据初始reducer来创建store,并使用store.subscribe来监听store变化时的操作
- 书写action,来承载每次修改store的变化
- 在交互等情况使用dispatch一个相应的action,
- reducer来响应action,并更新store,[store.subscribe监听函数将会被执行来驱动页面变化]
import { createStore } from 'redux';
/**
* 这是一个 reducer,形式为 (state, action) => state 的纯函数。
* 描述了 action 如何把 state 转变成下一个 state。
*
* state 的形式取决于你,可以是基本类型、数组、对象、
* 甚至是 Immutable.js 生成的数据结构。惟一的要点是
* 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
*
* 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)
* 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// 创建 Redux store 来存放应用的状态。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);
// 可以手动订阅更新,也可以事件绑定到视图层。
store.subscribe(() =>
console.log(store.getState())
);
// 改变内部 state 惟一方法是 dispatch 一个 action。
// action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1
异步redux
像 redux-thunk 或 redux-promise 这样支持异步的 middleware 都包装了 store 的 dispatch() 方法,以此来让你 dispatch 一些除了 action 以外的其他内容,例如:函数或者 Promise。
redux-react
Redux 官方提供的 React 绑定库。 具有高效且灵活的特性。
结合react来完善了下redux的使用,不需要我们每次都使用store.subscribe
来监听store的变化,提供了新的接口:
<Provider store>
可以在最顶层将store传递至每个需要store的子组件
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
可以将一些state映射到某个组件,来驱动组件渲染
总结
react-redux-demo
需要webpack3以上
运行方式:
`npm install` 安装相关依赖
`webpack` 执行webpack来进行打包
在浏览器中打开目录下的/html/pages/home.html
文件即可访问结果
➜ react-redux-demo git:(master) tree -I node_modules
.
├── html
│ └── pages
│ └── home.html
├── package-lock.json
├── package.json
├── readMe.md
├── src
│ ├── dist
│ │ ├── css
│ │ │ └── home.css
│ │ ├── images
│ │ │ └── head.jpeg
│ │ └── js
│ │ └── home.js
│ ├── scripts
│ │ ├── common
│ │ └── pages
│ │ └── home
│ │ ├── actions
│ │ │ ├── data.js
│ │ │ └── index.js
│ │ ├── components
│ │ │ ├── app.js
│ │ │ ├── article
│ │ │ │ └── index.js
│ │ │ └── consults
│ │ │ └── index.js
│ │ ├── index.js
│ │ ├── reducers
│ │ │ ├── data.js
│ │ │ └── index.js
│ │ └── store
│ │ └── index.js
│ └── styles
│ ├── images
│ │ └── home
│ │ └── head.jpeg
│ ├── lib
│ │ └── base.scss
│ ├── module
│ └── pages
│ └── home.scss
└── webpack.config.js
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。